Skip to content

docs: annotate 18 bare const schema = { literals so the snippet gate reads a declared type - #8487

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-8125-doc-schema-annotation-sweep
Sep 8, 2026
Merged

docs: annotate 18 bare const schema = { literals so the snippet gate reads a declared type#8487
baozhoutao merged 2 commits into
mainfrom
claude/issue-8125-doc-schema-annotation-sweep

Conversation

@claude

@claude claude Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Fixes #8125

check:doc-snippets compiles every covered ts/tsx block, but a block whose literal carries no annotation is judged against nothing: the gate reports it as JUDGED while consulting no declared type for it. objectui#7972 measured the cost — objectui#7713's wrong-shaped filter sat green on objectos-integration.mdx for its whole interval, and one annotation would have turned it red with exactly one diagnostic.

Why one sweep and not fourteen cards

The population reading is the argument. Triage read 30 bare literals across 15 pages at 05:26Z; the card measured 29/14 on 083e1abbf; this branch measures 28/13 on 76573a184. objectui#7778's sweep (PR #8040) took plugin-gantt.mdx's four across, and objectui#7972 (PR #8124) took one more — and the total moved by one. The ratchet shrinks at roughly the rate new bare literals are written, so net progress is about zero and fourteen more single-page cards would buy the same nothing.

Re-derived population, and a correction to the census

Re-run on origin/main 76573a184 in a dedicated worktree, with triage's own spelling:

reading count pages
bare const schema = { (raw grep hits) 28 13
annotated const schema: TYPE = { 23 10

guide/objectos-integration.mdx is at 0 bare / 1 annotated, so PR #8124 did land.

The raw count over-counts by 2. git grep -c "const schema = {" is a whole-file grep and two of its hits are prose, not code — sentences that argue for annotation, outside any fence:

  • content/docs/plugins/plugin-form.mdx:394 — "so an un-annotated const schema = { … } type-checks whatever is written in it"
  • content/docs/plugins/plugin-grid.mdx:612 — "an un-annotated const schema = { … } type-checks no matter what is written in it"

So the real population is 26 code occurrences across 11 pages. Of those, 18 are annotated here and 8 are excluded below.

After this branch: 41 annotated, and the 10 remaining raw const schema = { hits are exactly the 2 prose sentences + the 8 exclusions.

The ceiling, measured — read this before believing the annotation guards more than it does

BaseSchema closes with [key: string]: any (objectui#7927), so an annotation does NOT catch a misspelled or undeclared key. It catches a key whose declared TYPE is wrong. That is not a caveat inherited from a card, it is measured on this branch. Three legs, each mutating content/docs/plugins/plugin-editor.mdx on the committed tree and each restored to a byte-identical blob (git checkout HEAD -- path, verified by git hash-object against the HEAD blob 5cb59b077c2407f4f468e331d2e936a88a31b400 and by an empty git diff HEAD):

leg injected into an annotated block gate result
the block really is compiled value: zzzUndefinedIdentifier, exit 1 plugin-editor.mdx:37:10 TS2304: Cannot find name 'zzzUndefinedIdentifier'.
the ceiling zzzUndeclaredKeyNobodyDeclares: 'x', exit 0 0 diagnostics — the index signature absorbs it
the capability readOnly: 'not-a-boolean', exit 1 plugin-editor.mdx:37:3 TS2322: Type 'string' is not assignable to type 'boolean or undefined'.

A reader who sees an annotation and infers a guarded key set is worse off than one who sees a bare literal. The middle row is why.

One block turned red — that is the finding, not an obstacle

Annotating content/docs/guide/schema-rendering.md produced exactly one diagnostic:

[semantic]  content/docs/guide/schema-rendering.md:35:13  TS2353: Object literal may only
  specify known properties, and 'type' does not exist in type 'SchemaNode[]'.

The page passed a single object to a page node's body. PageNodeSchema.body is declared SchemaNode[] (packages/types/src/layout.ts:781, docblock "Main content array"), while the sibling children on the same interface is SchemaNode | SchemaNode[].

The renderer disagrees with the type. FlatContent in packages/components/src/renderers/layout/page.tsx:266-272 reads schema.body || schema.children and normalizes a non-array into a one-element array, so a single-node body does render:

const content = schema.body || schema.children;
const nodes: SchemaNode[] = Array.isArray(content) ? content : content ? [content as SchemaNode] : [];

That is a contradiction between two shipped surfaces, so it is fixed to the type in the docs and filed — ⛔ the type is not widened here. The docs edit is body: [{ type: "text", content: "Hello" }]. The divergence is handed to the PM seat below.

Exclusions — 8 code occurrences deliberately left bare

Seven are DECLARED FRAGMENTS. A declared fragment is the one thing this gate does not compile, so an annotation on one is a claim the gate structurally cannot re-verify — and the family test triage applied to admit this fold is that each member is independently checkable by the gate's own per-block verdict. A fragment is not. Annotating them to drive a count to zero would put exactly the unverifiable assertion into the docs that this gate's own header calls worse than no marker at all.

site why it cannot be a member
guide/plugin-development.md:403 the reader's own plugin under construction — src/BoardImpl.test.tsx, a board schema no published type names
guide/schema-rendering.md:114 type: "my-component" — the reader's own registered component, unnamed by any type by construction
guide/schema-rendering.md:406 a bad/good contrast pair that declares schema twice in one fence
plugin-calendar.mdx:160 shape excerpt whose events is the reader's data (marker records the measured TS2552)
plugin-calendar.mdx:499 not a node schema at all — the literal is { objectName, calendar } with no type key; it is ObjectCalendar's component prop
plugin-charts.mdx:290 shape excerpt; salesData is the reader's rows
plugin-charts.mdx:302 shape excerpt; metricsData is the reader's rows

One is the ruling carried from objectui#7972 / objectui#7977. utilities/vscode-extension.mdx:100 is the Export to React command's product reproduced verbatim (PR #8112). Annotating it would make the documented output diverge from what the command actually emits, so it stays bare. Taking it up with the template is objectui#7976's class, not this card's.

What this PR deliberately does not do

Per the card's fourth ruling: no gate, no pin, no new scan population. Whether a gate should refuse a bare const schema = { in a content/docs block is a separate ruling this sweep must not pre-empt.

One reading for whoever takes that ruling, offered as data and not acted on here: triage's census spelling is keyed to the identifier schema, so it does not see bare schema literals under any other name. There are 8 of those in content/docs (blocks/index.mdx:71, guide/schema-rendering.md:367,370,371,372,374, plugin-markdown.mdx:178,208), several of which are prose sketches like { /* ... */ } that could never be annotated. Extending the sweep to them would be exactly the new scan population ruling 4 forbids.

Changes

Two commits.

  1. The sweep — 18 annotations across 8 pages, each one an import type line plus a type on the declaration, plus the one docs-to-type fix above. Types used: PageNodeSchema and CardSchema and ObjectMapSchema and ChartSchema from @object-ui/types; BarChartSchema and CodeEditorSchema and MarkdownSchema from the plugin package each page already documents.
  2. A pin re-declarationscripts/__tests__/check-doc-snippet-types.test.ts's README_SAMPLE_FENCE_LINE moved 206 to 207. The pin keys objectui#7555's specimen on its fence line deliberately, so that an edit above it forces a re-declaration rather than leaving a row that silently covers nothing; this sweep added one import line above it on that page. The constant already carries a running record of such moves (objectui#6972's +11 is the previous entry) and this one is appended to it. The pin still holds what it was written to hold.

Verification

All on the final head a5a67ad47, worktree clean.

pnpm check:doc-snippets — the prediction stated before running was that the judged-block count would not move, since no block is added, removed or re-marked; what changes is what 18 of them are judged against. It did not move:

  • before: Semantic phase: 632 of 632 block(s) judged, 0 failed. — exit 0
  • after the sweep, before the docs fix: 632 of 632 block(s) judged, 1 failed. — exit 1, the SchemaNode[] diagnostic above
  • final: Semantic phase: 632 of 632 block(s) judged, 0 failed. — exit 0, "Every covered documentation snippet compiles against the built types."

The gate's own controls passed on every run (resolution into packages/types/dist/index.d.ts, sentinel TS2305, positive 0, undeclared TS2307, root-declared TS2307). Its --build-filter closure was built first — 35/35 turbo tasks successful — so no run is an unbuilt-tree exit 2.

Other gates that read these pages, all exit 0: check:doc-types (1106 blocks, 891 type literals), check:doc-fences (227 documents), check:doc-examples, check:doc-example-readers, check-doc-links (17 scan roots), check-doc-expression-carriage (report-only), check:control-bytes (6714 files).

Tests: pnpm exec vitest run scripts/__tests__/121 files, 3630 tests, all passing. This suite is owed because the diff edits a file under scripts/; it also holds the doc-gate suites directly. The one failure this change produced was the fence-line pin, re-declared as that pin intends, and the suite is green after it.

node scripts/check-changeset-presence.mjs — run, not guessed: "9 file(s) changed, 0 of them published source of a package the release covers, 0 of them a manifest whose published contract moved ... no changeset is owed." No skip-changeset label is applied: in this repository the gate's verdict line is authoritative and that label is not this repo's mechanism.

node scripts/check-governed-queue-guard.mjs --test on all 9 paths — "NOT GOVERNED — 9 path(s) checked against 5 governed surface(s); none matched." This PR nonetheless opens draft and stays draft, per its dispatch.

Repository lint is not owed by this diff and that is a measurement rather than a skip: eslint.config.js scopes every rule block to files: ['**/*.{ts,tsx}'] (and narrower), so .md and .mdx are outside the linted population entirely. The one .ts file in the diff is covered by the vitest run above; no configuration in the diff can move the verdict on any untouched file, since no type-aware linting is enabled.


Generated by Claude Code

…e reads a declared type

`check:doc-snippets` compiles every covered ts/tsx block, but a block whose
literal carries no annotation is judged against nothing: the gate reports it as
JUDGED while consulting no declared type for it. objectui#7972 measured the
cost — objectui#7713's wrong-shaped `filter` sat green on
`objectos-integration.mdx` for its whole interval, and one annotation would have
turned it red with exactly one diagnostic.

Sweep, not a card per page: the population was 30/15 at 05:26Z, 29/14 on
`083e1abbf`, and 28/13 on `76573a184` — it shrinks about as fast as new bare
literals are written, so page-by-page cards buy no net progress.

Re-measured on `76573a184` with triage's own spelling. Of the 28 raw
`git grep -c "const schema = {"` hits, 2 are PROSE (`plugin-form.mdx:394` and
`plugin-grid.mdx:612` are sentences advocating annotation, not code), leaving 26
code occurrences across 11 pages. 18 are annotated here; the other 8 are excluded
with reasons in the PR body.

One block turned red, which is the point of the sweep rather than an obstacle:
`guide/schema-rendering.md` passed a single object to a `page` node's `body`, and
`PageNodeSchema.body` is declared `SchemaNode[]`. Fixed to the declared type
(wrapped in an array), NOT widened — the renderer's `FlatContent` does normalize
a single node, so type and renderer disagree, and that divergence is filed
separately.

The ceiling, stated so nobody over-reads this: `BaseSchema` closes with
`[key: string]: any` (objectui#7927), so these annotations do NOT catch a
misspelled key. They catch a key whose declared TYPE is wrong.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
…n (206 -> 207)

`README_SAMPLE_FENCE_LINE` keys the objectui#7555 specimen on its fence LINE in
`content/docs/plugins/plugin-markdown.mdx`, deliberately: the pin's own comment
says an edit above it must force a re-declaration here rather than leave a row
that silently covers nothing.

This sweep added one `import type { MarkdownSchema }` line to that page's first
block, which sits above the specimen, so the fence moved 206 -> 207. Re-declared,
and the reason appended to the running record the constant already carries
(objectui#6972's +11 is the previous entry).

The pin still holds what it was written to hold: the block at the new line is the
same specimen, its body still contains `npm install project-name`, and its AST
specifier set is still empty while the retired regex reader still finds
`project-name` in the template literal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhBNJcLRZLe8M87VcUgpKr
@claude

claude Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

LANDEDdomain:devx @ objectui execution seat, PM session session_01FhBNJcLRZLe8M87VcUgpKr, R46. PR #8487 merged 2026-09-08T02:49:08Z as 67299bf43; probe run on a clean extract of re-fetched origin/main, ⛔ never on the shared working tree, and ⛔ scoped to the eight edited pages.

page annotated declarations
core/schema-renderer.mdx · guide/quick-start.md · guide/schema-playground.md 1 · 1 · 1
guide/schema-rendering.md · plugins/plugin-charts.mdx 2 · 6
plugins/plugin-editor.mdx · plugins/plugin-map.mdx · plugins/plugin-markdown.mdx 4 · 2 · 3

The control is the one that matters, and it holds: the two prose sentences at plugin-form.mdx and plugin-grid.mdx — the population's own false positives, the ones the census counted as members while they argued for the sweep — are still present and still un-annotated, one occurrence each. ⇒ The sweep reached its subject and nothing further.

The four bare literals remaining on the edited pages are the declared exclusions, verified in the tree rather than taken from the report:

guide/schema-rendering.md:114     const schema = { type: "my-component", // ... component props }
plugin-charts.mdx:290             {/* doc-snippet: fragment — shape excerpt; `salesData` is the reader's own rows */}

⇒ One is an ellipsis fragment that cannot be annotated; the other carries an explicit doc-snippet: fragment marker. Both fail triage's own family test — each member independently checkable by the gate's per-block verdict — which is exactly why they were excluded with reasons instead of forced.

⚠️ This probe's first pattern was wrong, and it is the fourth such slip this round. ^const schema: reported 0 annotations on schema-renderer.mdx; the declaration is at :84 and reads const schema: PageNodeSchema = {indented, inside a function body in the snippet. An anchored pattern answered a question about a shape it had assumed. ⇒ Re-run allowing leading whitespace, and the reading above is the corrected one. ⭐ Fitting, on a card whose own finding is that an instrument counted its own justification.

pm:dispatched stripped in the same pass; domain:devx, documentation, priority:p3 stay. The card closed via Fixes.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

2 participants